﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Windows.UI.Xaml.Controls;
using Goalchee.Common;

namespace Goalchee.DataModel
{
    #region Class DataServiceCall
    public class DataServiceCall : BindableBase
    {
        #region Private Variables
        private const string ThingsUrl = "http://www.43Things.com/service/";
        private const string SearchGoals = "search_goals";
        private const string SearchGoalsForTag = "get_tags_goals";
        private const string GoalsById = "get_goals_by_id";
        private const string PersonByGoals = "get_goals_people";
        private const string PopularGoals = "get_popular_tags";
        private const string Apikey = "545008@43rtF0IcpguS2";
        private string _title = string.Empty;
        private string _totalGoals = string.Empty;
        public string Title
        {
            get { return _title; }
            set
            {
                if ( this._title != value )
                {
                    this._title = value;
                    this.OnPropertyChanged ( "Title" );
                }
            }
        }
        public string TotalGoals
        {
            get { return _totalGoals; }
            set
            {
                if ( this._totalGoals != value )
                {
                    this._totalGoals = value;
                    this.OnPropertyChanged ( "TotalGoals" );
                }
            }
        }
        #endregion

        #region Popular Tags
        public Task<string> GetPopularTags ( )
        {
            HttpClient client = new HttpClient ( );
            string popularTags = string.Format ( "{0}{1}?api_key={2}", ThingsUrl, PopularGoals, Apikey );
            return client.GetStringAsync ( popularTags );
        }

        public List<Tag> ReadPopularTags ( Task<string> s )
        {
            string localVariable = s.Result;
            XDocument xdoc = XDocument.Parse ( localVariable );
            return xdoc.DescendantNodes ( ).
                Where ( node => node.GetType ( ) == typeof ( XElement ) ).
                Where ( node => ( ( ( XElement ) node ) ).
                Name.LocalName.Equals ( "tag" ) ).
                Select ( node => new Tag { TagName = ( ( XElement ) ( node ) ).Value } ).ToList ( );
        }
        #endregion

        #region Search Tags
        public Task<string> GetSearchTags ( string s )
        {
            HttpClient client = new HttpClient ( );
            string searchTags = string.Format ( "{0}{1}?q={2}&api_key={3}", ThingsUrl, SearchGoals, s, Apikey );
            return client.GetStringAsync ( searchTags );
        }

        public Task<string> GetGoalsById ( string goalId )
        {
            HttpClient client = new HttpClient ( );
            string searchTags = string.Format ( "{0}{1}?&api_key={2}&id={3}", ThingsUrl, GoalsById, Apikey, goalId );
            return client.GetStringAsync ( searchTags );
        }
        #endregion

        #region Search Goals for Tag
        public Task<string> GetSearchGoalsForTag ( string s )
        {
            HttpClient client = new HttpClient ( );
            string searchTags = string.Format ( "{0}{1}?&api_key={2}&id={3}", ThingsUrl, SearchGoalsForTag, Apikey, s );
            return client.GetStringAsync ( searchTags );
        }

        public List<GoalData> ReadSearchGoalsFromTags ( Task<string> s )
        {
            XDocument xdoc = XDocument.Parse ( s.Result );
            IEnumerable<XElement> xmlelements = from x in xdoc.Descendants ( ) select x;
            //xmlelements.Where ( xele => xele.Name.LocalName.Equals ( "title" ) ).Select ( xele => Title = ( ( XElement ) xele.FirstNode ).Value );
            foreach ( XElement xmlelement in xmlelements.Where ( xmlelement => xmlelement.Name.LocalName.Equals ( "pagination" ) ) )
            {
                TotalGoals = ( ( XElement ) xmlelement.FirstNode.NextNode.NextNode ).Value;
            }
            return xmlelements.Where ( xele => xele.Name.LocalName.Equals ( "goal" ) ).
                Select ( xele => new GoalData
                                   {
                                       GoalId = xele.FirstAttribute.Value ?? "0",
                                       Name = ( ( XElement ) ( xele.FirstNode ) ).Value ?? string.Empty,
                                       Link = ( ( XElement ) ( ( xele.FirstNode ).NextNode ) ).FirstAttribute.Value ?? string.Empty,
                                       NumRegisteredPeople = ( ( XElement ) ( ( ( xele.FirstNode ).NextNode ).NextNode ) ).Value ?? "0"
                                   } ).ToList ( );
        }
        #endregion

        #region Person By Goal
        public Task<string> GetPersonByGoals ( string goalId )
        {
            HttpClient client = new HttpClient ( );
            string searchTags = string.Format ( "{0}{1}?&api_key={2}&id={3}", ThingsUrl, PersonByGoals, Apikey, goalId );
            return client.GetStringAsync ( searchTags );
        }

        public List<Person> ReadPersonByGoals ( Task<string> s )
        {
            XDocument xdoc = XDocument.Parse ( s.Result );
            IEnumerable<XElement> xmlelements = from x in xdoc.Descendants ( ) select x;
            return xmlelements.Where ( xele => xele.Name.LocalName.Equals ( "person" ) ).
                Select ( xele => new Person
                                   {
                                       PersonId = xele.FirstAttribute.Value ?? "0",
                                       Username = ( ( XElement ) xele.FirstNode ).Value ?? string.Empty,
                                       PersonName = ( ( XElement ) xele.FirstNode.NextNode ).Value ?? string.Empty,
                                       OpenGoalsNumber = ( ( XElement ) xele.FirstNode.NextNode.NextNode.NextNode ).Value ?? "0",
                                       ProfileImageUrl = ( ( XElement ) xele.FirstNode.NextNode.NextNode.NextNode.NextNode ).Value ?? string.Empty,
                                       NumEntries = ( ( XElement ) xele.FirstNode.NextNode.NextNode.NextNode.NextNode.NextNode ).Value == null ? "0" : ( ( XElement ) xele.FirstNode.NextNode.NextNode.NextNode.NextNode.NextNode ).Value,
                                       //Link = ( ( ( XElement ) xele.FirstNode.NextNode.NextNode.NextNode.NextNode ).FirstAttribute ).Value;
                                   } ).ToList ( );
        }
        #endregion
    }
    #endregion

    #region Class Tag
    public class Tag : INotifyPropertyChanged
    {
        private string _tagName = string.Empty;

        public string TagName
        {
            get { return _tagName; }
            set
            {
                if ( this._tagName != value )
                {
                    this._tagName = value;
                    this.OnPropertyChanged ( "TagName" );
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged ( string propertyName )
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if ( handler != null )
                handler ( this, new PropertyChangedEventArgs ( propertyName ) );
        }
    }
    #endregion

    #region Class GoalData
    public class GoalData : INotifyPropertyChanged
    {
        private string _goalId = string.Empty;
        private string _name = string.Empty;
        private string _link = string.Empty;
        private string _numRegisteredPeople = string.Empty;

        public string GoalId
        {
            get { return _goalId; }
            set
            {
                if ( this._goalId != value )
                {
                    this._goalId = value;
                    this.OnPropertyChanged ( "GoalId" );
                }
            }
        }
        public string Name
        {
            get { return _name; }
            set
            {
                if ( this._name != value )
                {
                    this._name = value;
                    this.OnPropertyChanged ( "Name" );
                }
            }
        }
        public string Link
        {
            get { return _link; }
            set
            {
                if ( this._link != value )
                {
                    this._link = value;
                    this.OnPropertyChanged ( "Link" );
                }
            }
        }
        public string NumRegisteredPeople
        {
            get { return _numRegisteredPeople; }
            set
            {
                if ( this._numRegisteredPeople != value )
                {
                    this._numRegisteredPeople = value;
                    this.OnPropertyChanged ( "NumRegisteredPeople" );
                }
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged ( string propertyName )
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if ( handler != null )
                handler ( this, new PropertyChangedEventArgs ( propertyName ) );
        }
        #endregion
    }
    #endregion

    #region Class Person

    public class Person : INotifyPropertyChanged
    {
        private string _personid = string.Empty;
        private string _username = string.Empty;
        private string _personname = string.Empty;
        private string _numOpenGoals = string.Empty;
        private string _profileImageUrl = string.Empty;
        private string _link = string.Empty;
        private string _numEntries = string.Empty;

        public string PersonId
        {
            get { return _personid; }
            set
            {
                if ( this._personid != value )
                {
                    this._personid = value;
                    this.OnPropertyChanged ( "PersonId" );
                }
            }
        }

        public string Username
        {
            get { return _username; }
            set
            {
                if ( this._username != value )
                {
                    this._username = value;
                    this.OnPropertyChanged ( "Username" );
                }
            }
        }

        public string PersonName
        {
            get { return _personname; }
            set
            {
                if ( this._personname != value )
                {
                    this._personname = value;
                    this.OnPropertyChanged ( "PersonName" );
                }
            }
        }

        public string OpenGoalsNumber
        {
            get { return _numOpenGoals; }
            set
            {
                if ( this._numOpenGoals != value )
                {
                    this._numOpenGoals = value;
                    this.OnPropertyChanged ( "OpenGoalsNumber" );
                }
            }
        }

        public string ProfileImageUrl
        {
            get { return _profileImageUrl; }
            set
            {
                if ( this._profileImageUrl != value )
                {
                    this._profileImageUrl = value;
                    this.OnPropertyChanged ( "ProfileImageUrl" );
                }
            }
        }

        public string Link
        {
            get { return _link; }
            set
            {
                if ( this._link != value )
                {
                    this._link = value;
                    this.OnPropertyChanged ( "Link" );
                }
            }
        }

        public string NumEntries
        {
            get { return _numEntries; }
            set
            {
                if ( this._numEntries != value )
                {
                    this._numEntries = value;
                    this.OnPropertyChanged ( "NumEntries" );
                }
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        protected virtual void OnPropertyChanged ( string propertyName )
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if ( handler != null )
                handler ( this, new PropertyChangedEventArgs ( propertyName ) );
        }
    }

    #endregion
}